﻿using ShiQuan.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Script.Serialization;
using System.Windows.Forms;
using System.Xml;

namespace ShiQuan.AppUpdateBLL
{
    /// <summary>
    /// 执行委托
    /// </summary>
    /// <param name="index"></param>
    /// <param name="msg"></param>
    public delegate void OnProcess(int index, string msg);
    /// <summary>
    /// 程序更新业务处理
    /// </summary>
    public class AppUpdaterBLL
    {
        /// <summary>
        /// 程序文件
        /// </summary>
        public string AppLocalFile
        { get; set; }
        /// <summary>
        /// 本地程序信息
        /// </summary>
        public AppLocalInfo AppLocalInfo
        {
            get;
            private set;
        }
        /// <summary>
        /// 服务器程序信息
        /// </summary>
        public AppServerInfo AppServerInfo
        {
            get;
            private set;
        }
        /// <summary>
        /// 执行中
        /// </summary>
        public event OnProcess UpdateProcess = null;
        /// <summary>
        /// 检查更新
        /// </summary>
        public bool CheckUpdate(string appPath)
        {
            this.AppendText(0, "开始检查更新...");
            string error = string.Empty;
            this.AppendText(10, "获取本地程序文件信息...");
            AppLocalInfo appLocalInfo = this.GetLocalInfo(appPath, out error);
            if (appLocalInfo == null)
            {
                this.AppendText(100,  error);
                return false;
            }
            this.AppendText(20, "获取服务器程序文件信息..."+ appLocalInfo.ServerUrl);
            AppServerInfo appServerInfo = this.GetServerInfo(appLocalInfo.ServerUrl, out error);
            if (appServerInfo == null)
                return false;

            return this.CheckUpdate(appLocalInfo, appServerInfo);
        }

        /// <summary>
        /// 获取本地程序信息
        /// </summary>
        /// <param name="appPath"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public AppLocalInfo GetLocalInfo(string appPath, out string error)
        {
            error = string.Empty;
            if (string.IsNullOrEmpty(appPath))
                appPath = System.IO.Directory.GetParent(Application.StartupPath).FullName;

            //string mParentPath = System.IO.Path.GetFullPath(AppDomain.CurrentDomain.BaseDirectory);
            //读取本地程序信息
            AppLocalFile = System.IO.Path.Combine(appPath, "AppUpdater.xml");
            if (System.IO.File.Exists(AppLocalFile) == false)
            {
                error = "未能找到配置:" + AppLocalFile;
                Logger.Error(error);
                return null;
            }
            this.AppLocalInfo = new AppLocalInfo();
            this.AppLocalInfo.InitValue(AppLocalFile);
            return this.AppLocalInfo;
        }
        /// <summary>
        /// 获取服务器程序信息
        /// </summary>
        /// <param name="serverurl"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public AppServerInfo GetServerInfo(string serverurl, out string error)
        {
            error = string.Empty;
            try
            {
                //获取服务器程序信息
                var mAppServerInfo = WebRequestHelper.Get(serverurl);
                if (string.IsNullOrEmpty(mAppServerInfo))
                {
                    error = "未能获取到服务器程序信息！";
                    Logger.Error(error);
                    return null;
                }
                Logger.Info("下载结果：" + mAppServerInfo);
                XmlDocument doc = new XmlDocument();
                doc.LoadXml(mAppServerInfo);
                this.AppServerInfo = new AppServerInfo();
                this.AppServerInfo.InitValue(doc);
                return this.AppServerInfo;
            }
            catch (Exception ex)
            {
                Logger.Error("获取服务器程序信息异常：" + ex.ToString());
                return null;
            }
        }

        /// <summary>
        /// 获取服务器程序信息
        /// </summary>
        /// <param name="serverurl"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public AppServerInfo GetServerInfo(AppLocalInfo appLocal, out string error)
        {
            error = string.Empty;
            try
            {
                /*2022-05-01 侯连文 直接从服务器上下载Xml文件进行解释*/
                var mAppServerInfo = WebRequestHelper.Get(appLocal.ServerUrl);
                if (string.IsNullOrEmpty(mAppServerInfo))
                {
                    error = "未能获取到服务器程序信息！";
                    Logger.Error(error);
                    return null;
                }
                Logger.Info("下载结果：" + mAppServerInfo);
                //var requestResult = json.Deserialize<RequestResult<AppServerInfo>>(mAppServerInfo);
                //if(requestResult == null)
                //{
                //    error = "解释内容失败!";
                //    Logger.Error(error);
                //    return null;
                //}
                //if(requestResult.code != 0)
                //{
                //    error = "请求结果失败："+requestResult.msg;
                //    Logger.Error(error);
                //    return null;
                //}
                XmlDocument doc = new XmlDocument();
                doc.LoadXml(mAppServerInfo);
                //return requestResult.result;
                AppServerInfo appServer = new AppServerInfo();
                appServer.InitValue(doc);
                return appServer;
            }
            catch (Exception ex)
            {
                Logger.Error("获取服务器程序信息异常：" + ex.ToString());
                return null;
            }
        }
        /// <summary>
        /// 检查是否需要更新
        /// </summary>
        /// <param name="appPath"></param>
        public bool CheckUpdate(AppLocalInfo appLocalInfo, AppServerInfo appServerInfo)
        {
            //判断是否有更新程序下载
            Logger.Info("本地程序版本：" + appLocalInfo.Version + " 服务器程序版本：" + appServerInfo.Version);
            long mLocalVersion = 0, mServerVersion = 0;

            long.TryParse(appLocalInfo.Version.Replace(".", ""), out mLocalVersion);

            long.TryParse(appServerInfo.Version.Replace(".", ""), out mServerVersion);

            return mServerVersion > mLocalVersion;
        }
        /// <summary>
        /// 下载更新程序
        /// </summary>
        /// <param name="localInfo"></param>
        /// <param name="serverInfo"></param>
        public bool KillService(AppLocalInfo localInfo, out string error)
        {
            error = string.Empty;
            try
            {
                //判断是否需要关闭进程及服务程序
                this.AppendText(1, "判断是否需要关闭进程程序..." + localInfo.KillProcess);
                if (string.IsNullOrEmpty(localInfo.KillProcess) == false)
                {
                    string[] mKillProcess = localInfo.KillProcess.Split(';');
                    for (int index = 0; index < mKillProcess.Length; index++)
                    {
                        if(WinProcessHelper.Kill(mKillProcess[index],out error) == false)
                        {
                            error = "无法关闭应用程序:" + mKillProcess[index];
                            return false;
                        }
                    }
                }
                this.AppendText(5, "判断是否需要关闭服务程序..." + localInfo.StopServices);
                if (string.IsNullOrEmpty(localInfo.StopServices) == false)
                {
                    string[] mStopServices = localInfo.StopServices.Split(';');
                    if(WinServiceHelper.Stop(mStopServices,out error) == false)
                    {
                        return false;
                    }
                }
                return true;
            }
            catch (Exception ex)
            {
                this.AppendText(100, "下载更新程序包异常:" + ex.ToString());
                return false;
            }
            
        }
        /// <summary>
        /// 下载并更新文件
        /// </summary>
        /// <param name="appPath"></param>
        /// <param name="serverInfo"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public bool Update(string appPath,AppServerInfo serverInfo,out string error)
        {
            error = string.Empty;
            //string appPath = string.Empty;
            try
            {
                //下载更新程序
                this.AppendText(10, "下载更新程序包:" + serverInfo.Url);
                string mPackName = System.IO.Path.GetFileNameWithoutExtension(serverInfo.Url);
                string mSaveFile = System.IO.Path.Combine(Application.StartupPath, mPackName + ".zip");
                bool result = WebClientHelper.Download(serverInfo.Url, mSaveFile, out error);
                if (result == false)
                {
                    this.AppendText(100, error);
                    return false;
                }
                //解压更新程序文件
                this.AppendText(20, "解压更新程序文件:" + mSaveFile);
                ZipFileHelper.DeCompress(mSaveFile, Application.StartupPath);

                //appPath = System.IO.Directory.GetParent(Application.StartupPath).FullName;
                //更新文件
                this.AppendText(50, "更新文件..." + appPath);
                string mPackPath = System.IO.Path.Combine(Application.StartupPath, mPackName);
                string appZipFile = string.Empty;
                ZipFileHelper.Copy(mPackPath, this.AppLocalFile, appPath, ref appZipFile);
                //删除目录
                System.IO.Directory.Delete(mPackPath, true);
                //删除文件
                System.IO.File.Delete(mSaveFile);
                return true;
            }
            catch (Exception ex)
            {
                this.AppendText(100, "更新程序文件异常:" + ex.ToString());
                return false;
            }
        }
        /// <summary>
        /// 启动程序及服务
        /// </summary>
        /// <param name="appPath"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public bool StartService(string appPath,out string error)
        {
            error = string.Empty;
            try
            {
                //重新获取本地程序信息
                this.AppendText(80, "重新获取本地程序信息...");
                var localInfo = this.GetLocalInfo(appPath, out error);
                if (localInfo == null)
                {
                    this.AppendText(100, "本地程序信息为空：" + error);
                    return false;
                }
                //判断是否需要重启程序及服务程序
                this.AppendText(90, "判断是否需要重启程序及服务程序..." + localInfo.StartServices);
                if (string.IsNullOrEmpty(localInfo.StartServices) == false)
                {
                    string[] mStartServices = localInfo.StartServices.Split(';');
                    WinServiceHelper.Start(mStartServices);
                }

                this.AppendText(90, "判断是否需要重启程序及服务程序..." + localInfo.StartProcess);
                if (string.IsNullOrEmpty(localInfo.StartProcess) == false)
                {
                    string[] mStartProcess = localInfo.StartProcess.Split(';');
                    foreach (var item in mStartProcess)
                    {
                        string appFile = System.IO.Path.Combine(appPath, item + ".exe");
                        if (System.IO.File.Exists(appFile) == false)
                            continue;

                        WinProcessHelper.Start(appFile);
                    }
                }
                this.AppendText(100, "完成程序更新！");
                return true;
            }
            catch (Exception ex)
            {
                this.AppendText(100, "判断启动程序异常:" + ex.ToString());
                return false;
            }
        }

        private void AppendText(int index, string msg)
        {
            Logger.Info(msg);
            if (this.UpdateProcess != null)
                this.UpdateProcess(index, msg);
        }
    }
}
